from fastapi import APIRouter, Depends, HTTPException, Query, Path, Body
from sqlalchemy.orm import Session
from app.database.database import get_db
from app.services.auth_service import get_current_user
from fastapi.security import OAuth2PasswordBearer
from app.database.models import User
from typing import List, Optional, Dict, Any
from app.schemas.backup_schema import (
    BackupTaskCreate, BackupTaskUpdate, BackupTaskResponse,
    BackupFileResponse, PaginatedBackupTaskResponse, PaginatedBackupFileResponse
)
from app.services.backup_service import (
    create_backup_task, get_backup_task, update_backup_task, delete_backup_task,
    list_backup_tasks, execute_backup, list_backup_files, get_backup_file_url,
    restore_from_backup, batch_restore_from_backup
)
from app.utils.response_utils import ResponseResult
import logging
from pydantic import BaseModel, Field
from fastapi import Request
import time

# 配置日志记录器
logger = logging.getLogger(__name__)

oauth2_scheme = OAuth2PasswordBearer(
    tokenUrl="/auth/oauth/token",
    scheme_name="OAuth2PasswordBearer",
    auto_error=True
)

router = APIRouter(
    prefix="/api",
    tags=["备份管理"],
    responses={
        401: {"description": "未认证"},
        403: {"description": "无权限访问"},
        404: {"description": "资源不存在"},
        500: {"description": "服务器内部错误"}
    }
)

async def get_current_user_from_token(
    token: str = Depends(oauth2_scheme),
    db: Session = Depends(get_db)
) -> User:
    """从token中获取当前用户"""
    return get_current_user(db, token)


@router.post(
    "/backup/tasks",
    summary="创建备份任务",
    description="创建一个新的备份任务，可以指定备份的目录、计划类型和是否增量备份。",
    response_model=ResponseResult[BackupTaskResponse]
)
async def create_backup_task_endpoint(
    request: Request,
    task_data: BackupTaskCreate,
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求创建备份任务")
    
    task = create_backup_task(
        db=db,
        user_id=current_user.id,
        task_name=task_data.task_name,
        source_directory_ids=task_data.source_directory_ids,
        schedule_type=task_data.schedule_type,
        is_incremental=task_data.is_incremental
    )
    
    logger.info(f"用户 {current_user.id} 创建备份任务成功，任务ID: {task.id}, 耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[BackupTaskResponse](
        code=200,
        message="创建备份任务成功",
        data=task
    )


@router.get(
    "/backup/tasks",
    summary="获取备份任务列表",
    description="获取当前用户的备份任务列表，支持分页和筛选。",
    response_model=ResponseResult[PaginatedBackupTaskResponse]
)
async def list_backup_tasks_endpoint(
    request: Request,
    page: int = Query(1, description="页码，从1开始"),
    page_size: int = Query(20, description="每页数量，默认20，最大100"),
    schedule_type: Optional[str] = Query(None, description="计划类型筛选"),
    status: Optional[str] = Query(None, description="任务状态筛选"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求获取备份任务列表")
    
    result = list_backup_tasks(
        db=db,
        user_id=current_user.id,
        page=page,
        page_size=page_size,
        schedule_type=schedule_type,
        status=status
    )
    
    logger.info(f"用户 {current_user.id} 获取备份任务列表成功，返回 {len(result['items'])} 条记录，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[PaginatedBackupTaskResponse](
        code=200,
        message="获取备份任务列表成功",
        data=result
    )


@router.get(
    "/backup/tasks/{task_id}",
    summary="获取备份任务详情",
    description="获取指定备份任务的详细信息。",
    response_model=ResponseResult[BackupTaskResponse]
)
async def get_backup_task_endpoint(
    request: Request,
    task_id: int = Path(..., description="备份任务ID"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求获取备份任务 {task_id} 详情")
    
    task = get_backup_task(
        db=db,
        task_id=task_id,
        user_id=current_user.id
    )
    
    # 尝试解析源目录信息
    try:
        import json
        from app.database.models import Directory
        
        source_directory_ids = json.loads(task.source_directory_ids) if task.source_directory_ids else []
        
        if source_directory_ids:
            directories = db.query(Directory).filter(Directory.id.in_(source_directory_ids)).all()
            task.source_directories = [
                {
                    "id": dir.id,
                    "name": dir.name,
                    "path": dir.path
                }
                for dir in directories
            ]
        else:
            task.source_directories = []
            
    except Exception as e:
        logger.error(f"解析备份任务源目录信息错误: {str(e)}")
        task.source_directories = []
    
    logger.info(f"用户 {current_user.id} 获取备份任务 {task_id} 详情成功，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[BackupTaskResponse](
        code=200,
        message="获取备份任务详情成功",
        data=task
    )


@router.put(
    "/backup/tasks/{task_id}",
    summary="更新备份任务",
    description="更新指定备份任务的信息，如任务名称、计划类型等。",
    response_model=ResponseResult[BackupTaskResponse]
)
async def update_backup_task_endpoint(
    request: Request,
    task_id: int = Path(..., description="备份任务ID"),
    task_data: BackupTaskUpdate = Body(...),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求更新备份任务 {task_id}")
    
    task = update_backup_task(
        db=db,
        task_id=task_id,
        user_id=current_user.id,
        task_name=task_data.task_name,
        source_directory_ids=task_data.source_directory_ids,
        schedule_type=task_data.schedule_type,
        is_incremental=task_data.is_incremental
    )
    
    logger.info(f"用户 {current_user.id} 更新备份任务 {task_id} 成功，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[BackupTaskResponse](
        code=200,
        message="更新备份任务成功",
        data=task
    )


@router.delete(
    "/backup/tasks/{task_id}",
    summary="删除备份任务",
    description="删除指定的备份任务。可选择是否同时删除备份的文件。",
    response_model=ResponseResult[Dict[str, Any]]
)
async def delete_backup_task_endpoint(
    request: Request,
    task_id: int = Path(..., description="备份任务ID"),
    delete_backup_files: bool = Query(False, description="是否同时删除备份的文件"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求删除备份任务 {task_id}")
    
    result = delete_backup_task(
        db=db,
        task_id=task_id,
        user_id=current_user.id,
        delete_backup_files=delete_backup_files
    )
    
    logger.info(f"用户 {current_user.id} 删除备份任务 {task_id} 成功，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[Dict[str, Any]](
        code=200,
        message="删除备份任务成功",
        data=result
    )


@router.post(
    "/backup/tasks/{task_id}/execute",
    summary="执行备份任务",
    description="立即执行指定的备份任务。可选择是否强制进行全量备份。",
    response_model=ResponseResult[Dict[str, Any]]
)
async def execute_backup_task_endpoint(
    request: Request,
    task_id: int = Path(..., description="备份任务ID"),
    force_full_backup: bool = Query(False, description="是否强制执行全量备份"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求执行备份任务 {task_id}")
    
    result = execute_backup(
        db=db,
        task_id=task_id,
        user_id=current_user.id,
        force_full_backup=force_full_backup
    )
    
    logger.info(f"用户 {current_user.id} 执行备份任务 {task_id} 成功，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[Dict[str, Any]](
        code=200,
        message="执行备份任务成功",
        data=result
    )


@router.get(
    "/backup/tasks/{task_id}/files",
    summary="获取备份文件列表",
    description="获取指定备份任务的文件列表，支持分页和筛选。",
    response_model=ResponseResult[PaginatedBackupFileResponse]
)
async def list_backup_files_endpoint(
    request: Request,
    task_id: int = Path(..., description="备份任务ID"),
    page: int = Query(1, description="页码，从1开始"),
    page_size: int = Query(20, description="每页数量，默认20，最大100"),
    backup_type: Optional[str] = Query(None, description="备份类型筛选"),
    status: Optional[str] = Query(None, description="文件状态筛选"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求获取备份任务 {task_id} 的文件列表")
    
    result = list_backup_files(
        db=db,
        task_id=task_id,
        user_id=current_user.id,
        page=page,
        page_size=page_size,
        backup_type=backup_type,
        status=status
    )
    
    logger.info(f"用户 {current_user.id} 获取备份任务 {task_id} 的文件列表成功，返回 {len(result['items'])} 条记录，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[PaginatedBackupFileResponse](
        code=200,
        message="获取备份文件列表成功",
        data=result
    )


@router.get(
    "/backup/files/{backup_file_id}/url",
    summary="获取备份文件下载URL",
    description="获取指定备份文件的临时下载URL，有效期1小时。",
    response_model=ResponseResult[Dict[str, Any]]
)
async def get_backup_file_url_endpoint(
    request: Request,
    backup_file_id: int = Path(..., description="备份文件ID"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求获取备份文件 {backup_file_id} 的下载URL")
    
    result = get_backup_file_url(
        db=db,
        backup_file_id=backup_file_id,
        user_id=current_user.id
    )
    
    logger.info(f"用户 {current_user.id} 获取备份文件 {backup_file_id} 的下载URL成功，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[Dict[str, Any]](
        code=200,
        message="获取备份文件下载URL成功",
        data=result
    )


@router.post(
    "/backup/files/{backup_file_id}/restore",
    summary="从备份恢复单个文件",
    description="从备份中恢复单个文件。可选择是否覆盖原始文件。",
    response_model=ResponseResult[Dict[str, Any]]
)
async def restore_file_endpoint(
    request: Request,
    backup_file_id: int = Path(..., description="备份文件ID"),
    overwrite_existing: bool = Query(False, description="是否覆盖现有文件"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求从备份 {backup_file_id} 恢复文件")
    
    result = restore_from_backup(
        db=db,
        backup_file_id=backup_file_id,
        user_id=current_user.id,
        overwrite_existing=overwrite_existing
    )
    
    logger.info(f"用户 {current_user.id} 从备份 {backup_file_id} 恢复文件成功，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[Dict[str, Any]](
        code=200,
        message="从备份恢复文件成功",
        data=result
    )


class BatchRestoreRequest(BaseModel):
    """批量从备份恢复文件请求模型"""
    backup_file_ids: List[int] = Field(None, description="要恢复的备份文件ID列表，为空则恢复任务中的所有文件", example=[1, 2, 3])
    overwrite_existing: bool = Field(False, description="是否覆盖现有文件", example=False)
    
    class Config:
        schema_extra = {
            "example": {
                "backup_file_ids": [1, 2, 3],
                "overwrite_existing": False
            }
        }


@router.post(
    "/backup/tasks/{task_id}/restore",
    summary="批量从备份恢复文件",
    description="从指定备份任务中批量恢复文件。可选择是否覆盖原始文件。",
    response_model=ResponseResult[Dict[str, Any]]
)
async def batch_restore_files_endpoint(
    request: Request,
    task_id: int = Path(..., description="备份任务ID"),
    restore_data: BatchRestoreRequest = Body(...),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    start_time = time.time()
    logger.info(f"用户 {current_user.id} 请求从备份任务 {task_id} 批量恢复文件")
    
    result = batch_restore_from_backup(
        db=db,
        task_id=task_id,
        user_id=current_user.id,
        backup_file_ids=restore_data.backup_file_ids,
        overwrite_existing=restore_data.overwrite_existing
    )
    
    logger.info(f"用户 {current_user.id} 从备份任务 {task_id} 批量恢复文件成功，恢复 {result.get('restored_count', 0)} 个文件，耗时: {time.time() - start_time:.3f}秒")
    
    return ResponseResult[Dict[str, Any]](
        code=200,
        message="批量从备份恢复文件成功",
        data=result
    ) 